﻿using System;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;

namespace Odebrecht.WpfControls
{
    [TemplatePart(Name = CustomIntegerUpDownVisualElements.TextBoxPART, Type = typeof(TextBox))]
    [TemplatePart(Name = CustomIntegerUpDownVisualElements.IncreaseButtonPART, Type = typeof(RepeatButton))]
    [TemplatePart(Name = CustomIntegerUpDownVisualElements.DecreaseButtonPART, Type = typeof(RepeatButton))]
    [TemplateVisualState(GroupName = CustomIntegerUpDownVisualStates.FocusGroup, Name = CustomIntegerUpDownVisualStates.Focused)]
    [TemplateVisualState(GroupName = CustomIntegerUpDownVisualStates.FocusGroup, Name = CustomIntegerUpDownVisualStates.Unfocused)]
    public class CustomIntegerUpDown : Control
    {
        #region Fields

        public static readonly DependencyProperty ButtonVisibleOnFocusProperty = 
            DependencyProperty.Register("ButtonVisibleOnFocus", typeof(bool), typeof(CustomIntegerUpDown), new PropertyMetadata(false, new PropertyChangedCallback(ButtonVisibleOnFocusChangedCallback)));
        public static readonly DependencyProperty IsAnimatedProperty = 
            DependencyProperty.Register("IsAnimated", typeof(bool), typeof(CustomIntegerUpDown), new PropertyMetadata(true));
        public static readonly DependencyProperty ValueProperty = 
            DependencyProperty.Register("Value", typeof(int), typeof(CustomIntegerUpDown), new PropertyMetadata(0));

        private RepeatButton _decreaseButtonElement;
        private RepeatButton _increaseButtonElement;
        private TextBox _textBoxElement;

        #endregion Fields

        #region Constructors

        static CustomIntegerUpDown()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomIntegerUpDown), new FrameworkPropertyMetadata(typeof(CustomIntegerUpDown)));
        }

        #endregion Constructors

        #region Properties

        [Browsable(true)]
        [Category("Odebrecht")]
        [Description("Indica que o botão será visível somente no foco.")]
        public bool ButtonVisibleOnFocus
        {
            get { return (bool)GetValue(ButtonVisibleOnFocusProperty); }
            set { SetValue(ButtonVisibleOnFocusProperty, value); }
        }

        [Browsable(true)]
        [Category("Odebrecht")]
        [Description("IsAnimated")]
        public bool IsAnimated
        {
            get { return (bool)GetValue(IsAnimatedProperty); }
            set { SetValue(IsAnimatedProperty, value); }
        }

        [Browsable(true)]
        [Category("Odebrecht")]
        [Description("Indica que o valor.")]
        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        #endregion Properties

        #region Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (ButtonVisibleOnFocus)
            {
                VisualStateManager.GoToState(this, CustomIntegerUpDownVisualStates.Unfocused, false);
            }

            _textBoxElement = GetTemplateChild(CustomIntegerUpDownVisualElements.TextBoxPART) as TextBox;
            _increaseButtonElement = GetTemplateChild(CustomIntegerUpDownVisualElements.IncreaseButtonPART) as RepeatButton;
            _decreaseButtonElement = GetTemplateChild(CustomIntegerUpDownVisualElements.DecreaseButtonPART) as RepeatButton;

            if (_textBoxElement != null)
            {
                _textBoxElement.GotFocus += OnElementGotFocus;
                _textBoxElement.LostFocus += OnElementLostFocus;
                _textBoxElement.PreviewTextInput += TextBoxElementPreviewTextInput;
                SetTextBoxElementUnfocusedTextBinding();
            }

            if (_increaseButtonElement != null)
            {
                _increaseButtonElement.GotFocus += OnElementGotFocus;
                _increaseButtonElement.LostFocus += OnElementLostFocus;
                _increaseButtonElement.Click += IncreaseButtonElementClick;
            }

            if (_decreaseButtonElement != null)
            {
                _decreaseButtonElement.GotFocus += OnElementGotFocus;
                _decreaseButtonElement.LostFocus += OnElementLostFocus;
                _decreaseButtonElement.Click += DecreaseButtonElementClick;
            }
        }

        protected virtual void ButtonVisibleOnFocusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var buttonVisibleOnFocus = Convert.ToBoolean(e.NewValue);
            SetFocusState(!buttonVisibleOnFocus);
        }

        private static void ButtonVisibleOnFocusChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var customIntegerUpDown = sender as CustomIntegerUpDown;
            customIntegerUpDown.Dispatcher.Invoke(new Action(() =>
            {
                customIntegerUpDown.ButtonVisibleOnFocusChanged(sender, e);
            }));
        }

        private void DecreaseButtonElementClick(object sender, RoutedEventArgs e)
        {
            Value--;
        }

        private void IncreaseButtonElementClick(object sender, RoutedEventArgs e)
        {
            Value++;
        }

        private void OnElementGotFocus(object sender, RoutedEventArgs e)
        {
            SetTextBoxElementFocusedTextBinding();
            if (ButtonVisibleOnFocus) SetFocusState(true);
        }

        private void OnElementLostFocus(object sender, RoutedEventArgs e)
        {
            SetTextBoxElementUnfocusedTextBinding();
            if (ButtonVisibleOnFocus) SetFocusState(false);
        }

        private void SetFocusState(bool isFocus)
        {
            if (isFocus)
            {
                VisualStateManager.GoToState(this, CustomIntegerUpDownVisualStates.Focused, IsAnimated);
            }
            else
            {
                VisualStateManager.GoToState(this, CustomIntegerUpDownVisualStates.Unfocused, IsAnimated);
            }
        }

        private void SetTextBoxElementFocusedTextBinding()
        {
            BindingOperations.ClearBinding(_textBoxElement, TextBox.TextProperty);

            var binding = new Binding("Value");
            binding.Source = this;
            binding.Mode = BindingMode.TwoWay;
            _textBoxElement.SetBinding(TextBox.TextProperty, binding);
        }

        private void SetTextBoxElementUnfocusedTextBinding()
        {
            BindingOperations.ClearBinding(_textBoxElement, TextBox.TextProperty);

            var binding = new Binding("Value");
            binding.Source = this;
            binding.Mode = BindingMode.TwoWay;
            binding.StringFormat = "{0} dias";
            _textBoxElement.SetBinding(TextBox.TextProperty, binding);
        }

        private void TextBoxElementPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            Regex regex = new Regex("[^0-9]+");
            e.Handled = regex.IsMatch(e.Text);
        }

        #endregion Methods
    }
}